package itsm.isperp.framework.data.commons.repository;

import itsm.isperp.framework.collection.map.LowercaseKeyHashMap;
import itsm.isperp.framework.data.domain.DataRequest;
import itsm.isperp.framework.data.domain.QueryFilter;
import itsm.isperp.framework.domain.IBean;

import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Component;

/**
 * 基础的标准数据访问接口，支持对分页器的支持及动态查询
 * 
 * @author lizx
 * @date 2012-11-24 创建接口
 * @since V1.0
 * @date 2013-4-15 lizx 增加动态更新实体方法
 * @date 2013-8-7 lizx 调整动态更新实体方法
 */
@Component
public interface BaseRepository<T> extends GenericRepository<T, String>,
		PageableRepository<T> {

	/**
	 * 是否存在指定id的数据，如果为null则不存在否则返回1
	 * 
	 * @param id
	 *            唯一标识
	 * @param clazz
	 *            实体类的Class{@link Class}
	 * @return
	 */
	public Object existsByClass(String id, Class<? extends IBean> clazz);

	/**
	 * 根据实体类删除实体
	 * 
	 * @param id
	 *            唯一标识
	 * @param clazz
	 *            实体类的Class{@link Class}
	 */
	public void deleteByClass(String id, Class<T> clazz);

	/**
	 * 根据实体类删除实体所有数据
	 * 
	 * @param clazz
	 */
	public void deleteAll(Class<T> clazz);

	/**
	 * 
	 * 查找实体赋值在一个Map中,其中DataRequest用于指定查询的列
	 * 
	 * @param id
	 *            唯一标识
	 * @param clazz
	 *            实体类的Class{@link Class}
	 * @param selectColumns
	 *            查询的列
	 * @return 实体Map
	 */
	public Map<String, Object> findOneByClassAndColumns(String id,
			Class<T> clazz, String[] selectColumns);

	/**
	 * 查找实体赋值在一个Map中
	 * 
	 * @param id
	 *            唯一标识
	 * @param clazz
	 *            实体类的Class{@link Class}
	 * @return 实体Map
	 */
	public Map<String, Object> findOneByClass(String id, Class<T> clazz);

	/**
	 * 通过实体的Class查询一个Map的列表
	 * 
	 * @param clazz
	 *            实体类的Class{@link Class}
	 * @return Map的列表
	 */
	public List<LowercaseKeyHashMap<String, Object>> findAllByClass(
			Class<T> clazz);

	/**
	 * 
	 * @param clazz
	 * @param rfilte
	 * @return
	 */
	public List<LowercaseKeyHashMap<String, Object>> findAllByClassAndFilter(
			Class<T> clazz, QueryFilter rfilte);

	/**
	 * 
	 * 
	 * @param clazz
	 * @param request
	 * @return
	 */
	public Map<String, Object> findOneByClassAndRequest(
			@Param("clazz") Class<T> clazz,
			@Param("request") DataRequest request);

	/**
	 * 
	 * @param entity
	 * @param includeColumns
	 */
	void dynamicSpecificSave(T entity, Set<String> includeColumns);

	/**
	 * 动态更新实体，如果指定实体对象的字段不为空则将会持久化到数据库中，如果指定实体为空则将忽略
	 * 
	 * @param entity
	 *            实体对象
	 */
	// void dynamicUpdate(T entity);

	/**
	 * 通过对比两个实体的值跟新发生变化的实体字段.
	 * <p>
	 * e.g: <br>
	 * {@code MyEntity entity= new MyEntity() =>id="1",name="Lee",email="" ; 
	 * MyEntity oldEntity= new MyEntity() >id="1",name="Lee",email="Lee@mail.com"; }
	 * <br>
	 * 那么在更新实体时只会对字段email进行更新.
	 * </p>
	 * 
	 * @param entity
	 *            新的实体
	 * @param oldEntity
	 *            旧的实体
	 */
	// void dynamicUpdateEntity(T entity, T oldEntity);

	/**
	 * 动态更新指定字段的值.
	 * <p>
	 * e.g: <br>
	 * 
	 * {@code MyEntity e= new MyEntity() => id="1",name="Lee",email="" ;
	 * Set<String> sets= new HashSet<>(); sets.add("email"); } <br>
	 * 那么在更新实体时只会对字段email进行更新.
	 * </p>
	 * 
	 * @param entity
	 *            实体
	 * @param includeColumns
	 *            指定实体需要更新的字段的集合
	 */
	void dynamicSpecificUpdate(T entity, Set<String> includeColumns);

	/**
	 * 动态更新，但是可以通过unIncludeColumns忽略某些字段的更新
	 * <p>
	 * e.g: <br>
	 * 
	 * {@code MyEntity e= new MyEntity() => id="1",name="Lee",email="" ;
	 * Set<String> sets= new HashSet<>(); sets.add("email"); } <br>
	 * 那么在更新实体时<b>不会</b>对字段email进行更新.
	 * </p>
	 * 
	 * @param entity
	 *            实体
	 * @param unIncludeColumns
	 *            指定实体不需要更新的字段
	 */
	void dynamicButSpecificUpdate(T entity, Set<String> unIncludeColumns);

	/**
	 * 根据过滤条件获取所有，其结果列为 count_all
	 * 
	 * @param filter
	 * @return
	 */
	public Long findAllCount(@Param("clazz") Class<T> clazz,
			@Param("filter") QueryFilter filter);

	public int saveMap(@Param("tableName") String tableName,
			@Param("map") Map<String, Object> map);

}
